<?php
/**
 * Глобальный класс управления формами
 * 
 * @category Phorm
 * @package Resource
 * @name /Phorm/Resource/Forms.php
 * @copyright phorm.ru
 * @since 23.12.2010
 * @author vladimir@kachalov.net
 */

class Phorm_Resource_Forms extends Phorm_Resource {
	
	/**
	 * Id модуля
	 * @var string
	 */
	protected $_moduleid = 'forms';
	
	/**
	 * Конструктор
	 * 
	 * @return void
	 */
	
	public function __construct() {
		
		parent::__construct($this->_moduleid);
		
	}
	
	/**
	 * Возвращает список форм
	 * 
	 * @param array $opions Массив опций
	 * 
	 * @return array
	 */
	
	public function getFormsList($options=array()) {
			
		if($select = $this->getResourcesList($options+array('moduleid'=>$this->_moduleid,'return_as'=>'select'))) {
			
			$select -> joinLeft(array('PP'=>'pw_resources_forms'),'AA.resourceid=PP.resourceid', 
								new Zend_Db_Expr('(SELECT COUNT(*) FROM pw_resources_forms_entries WHERE resourceid=PP.resourceid) entries'))
					-> group('PP.resourceid');
								
			return $this->_db->fetchAll($select);
			
		} else {
			
			return false;
			
		}
			
	}
	
	/**
	 * Возвращает базовую информацию о форме (без привязки к таблице материалов сайта)
	 * 
	 * @param int $resourceid Id формы
	 * 
	 * @return array
	 */
		
	public function getFormInfo($resourceid) {
		
		$select = $this->_db->select()
				-> from('pw_resources_forms')
				-> where('resourceid=?',$resourceid);
			
		if($row = $this->_db->fetchRow($select)) {
				
			$row['fields'] = $this->getFieldsList($row['resourceid']);
				
			return $row;
				
		}
			
		return false;
			
	}
	
	
	/**
	 * Возвращает полную информацию о форме (с привязкой к таблице материалов сайта)
	 * 
	 * @param int $resourceid Id формы
	 * 
	 * @return array
	 */
		
	public function getFullFormInfo($resourceid) {
		
		if($ResourceInfo = $this->getResourceInfo($resourceid, array('moduleid'=>$this->_moduleid))) {
			
			if($FormInfo = $this->getFormInfo($ResourceInfo["resourceid"])) {
				
				return $ResourceInfo + $FormInfo;
				
			}
			
			return $ResourceInfo;
			
		}
		
		return false;
			
	}
	
	
	/**
	 * Возвращает список полей формы
	 *
	 * @param int $resourceid
	 * @return array
	 */
	
	public function getFieldsList($resourceid) {
		
		$select = $this->_db->select()
				-> from("pw_resources_forms_fields")
				-> where("resourceid=?",$resourceid)
				-> order("sortorder");
				
		return $this->_db->fetchAll($select);
		
	}
 	
	
	/**
	 * Сохраняет данные формы. Дополнительный метод при сохранении материала
	 * Предполагается, что этот метод будет вызываться из self::saveResourceForm поэтому трансакция БД не инициализируется
	 *
	 * @param array $data Массив данных формы, возвращаемый методом saveResourceForm
	 * @see Phorm_Resource::saveResourceForm
	 * @return array | false
	 */
	
	protected function saveFormInfo($data) {
		
		$result = false;
		
		if(isset($data['resourceid']) && $data['resourceid']>0) {
		
			/**
			 * Сохранение полей формы
			 */
			
			if(isset($data['fields']) && is_array($data['fields'])) {
				
				/**
				 * Удаление непереданных записей
				 * И модификация переданного массива
				 */
				
				$excluded = array();
				$position = 0;
							
				foreach ($data['fields'] as $key=>$field) {
					if(isset($field['fieldid']) && $field['fieldid']>0) $excluded[] = $field['fieldid'];
					$data['fields'][$key]['resourceid'] = $data['resourceid'];
					$data['fields'][$key]['sortorder'] = $position++;
				}
				
				if(empty($excluded)) {
					$this->_db->delete('pw_resources_forms_fields',"resourceid=".(int)$data['resourceid']);
				} else {
					$this->_db->delete('pw_resources_forms_fields',"resourceid=".(int)$data['resourceid']." AND fieldid NOT IN(".implode(",",$excluded).")");
				}
	
				foreach ($data['fields'] as $field) {
					
					// Изменение существующей записи
					
					if(isset($field['fieldid']) && $field['fieldid']>0) {
						
						$this->_db->update('pw_resources_forms_fields',$field,'fieldid='.(int)$field['fieldid']);
					
					// Вставка новой записи	
						
					} else {
						
						$this->_db->insert('pw_resources_forms_fields',$field);
						$data['fields']['resourceid'] = $this->_db->lastInsertId();
						
					}
	
				}
				
				$result = $data;
				
			}
			
			/**
			 * Сохранение дополнительных параметров
			 * Выделяем из массива данных поля для вставки в основную таблицу pw_resources_forms
			 * Удаляем запись из таблицы и вставляем новую
			 */
			
			$maindata = $this->getFilteredValuesByTableCols('pw_resources_forms',$data);
			$this->_db->delete('pw_resources_forms','resourceid='.(int)$data['resourceid']);
			$this->_db->insert('pw_resources_forms',$maindata);
		
		}
		
		return $result;
		
	}
	
	
	/**
	 * Строит форму
	 * 
	 * @param array $fields Массив данных о полях формы
	 * 
	 * @return Zend_Form
	 */
		
	public function buildForm($fields) {
			
		$form = Phorm_Form::makeForm();
			
		foreach ($fields as $data) {
				
			$fieldname = "field_".$data["fieldid"];
				
			switch ($data["fieldtype"]) {
					
				/**
				 * Однострочное текстовое поле
				 */
					
				case "Text":
						
					$field = new Zend_Form_Element_Text($fieldname);
						
					// Типы валидаторов
				
					if($data["fieldvalidators"]=="Email") {
							
						$field -> addValidator("EmailAddress",true,array("messages" => 
					   											array("emailAddressInvalid" => $this->_translate->_("Неверно указан email"),
				   													  "emailAddressInvalidHostname" => $this->_translate->_("Неверно указан email"),
						   											  "emailAddressInvalidMxRecord" => $this->_translate->_("Неверно указан email"),
						   											  "emailAddressInvalidSegment" => $this->_translate->_("Неверно указан email"),
						   											  "emailAddressDotAtom" => $this->_translate->_("Неверно указан email"),
						   											  "emailAddressQuotedString" => $this->_translate->_("Неверно указан email"),
						   											  "emailAddressInvalidLocalPart" => $this->_translate->_("Неверно указан email"),
						   											  "emailAddressLengthExceeded" => $this->_translate->_("Неверно указан email"),
						   											  "emailAddressInvalidFormat" => $this->_translate->_("Неверный формат"))));
					} elseif($data["fieldvalidators"]=="Date") {
							
						$field -> addValidator("Date",true,array("messages" => array("dateInvalid" => $this->_translate->_("Неверная дата"),
																					 "dateInvalidDate" => $this->_translate->_("Неверная дата"),
																					 "dateFalseFormat" => $this->_translate->_("Неверная дата"))));
							
					} elseif($data["fieldvalidators"]=="Int") {
							
						$field -> addValidator("Int",true,array("messages" => array("notInt" => $this->_translate->_("Значение должно быть числом"),
																						"intInvalid" => $this->_translate->_("Значение должно быть числом"))));
							
					} elseif($data["fieldvalidators"]=="Hostname") {
							
						$field -> addValidator("Hostname",true,array("messages" => array("hostnameInvalid" => $this->_translate->_("Неверный адрес"),
																						 "hostnameIpAddressNotAllowed" => $this->_translate->_("Неверный адрес"),
																						 "hostnameUnknownTld" => $this->_translate->_("Неверный адрес"),
																						 "hostnameDashCharacter" => $this->_translate->_("Неверный адрес"),
																						 "hostnameInvalidHostnameSchema" => $this->_translate->_("Неверный адрес"),
																						 "hostnameUndecipherableTld" => $this->_translate->_("Неверный адрес"),
																						 "hostnameInvalidHostname" => $this->_translate->_("Неверный адрес"),
																						 "hostnameInvalidLocalName" => $this->_translate->_("Неверный адрес"),
																						 "hostnameLocalNameNotAllowed" => $this->_translate->_("Неверный адрес"),
																						 "hostnameCannotDecodePunycode" => $this->_translate->_("Неверный адрес"))));
							
					}
						
					// Если разрешен HTML
				
					if($data["htmlallowed"]=="yes") {
							
						$field -> addFilter("StringTrim");
							
					} else {
							
						$field -> addFilter("StripTags");
							
					}
						
					break;
						
				/**
				 * Многострочное текстовое поле
				 */
					
				case "Textarea":
						
					$field = new Zend_Form_Element_Textarea($fieldname);
						
					// Если разрешен HTML
				
					if($data["htmlallowed"]=="yes") {
							
						$field -> addFilter("StringTrim");
							
					} else {
							
						$field -> addFilter("StripTags");
							
					}
						
					break;

				/**
				 * Чекбокс
				 */
					
				case "Checkbox":
						
					$field = new Zend_Form_Element_Checkbox($fieldname);
						
					break;
						
				/**
				 * Радиоточка
				 */
					
				case "Radio":
						
					$field = new Zend_Form_Element_Radio($fieldname);
						
					break;
						
				/**
				 * Список
				 */
					
				case "Select":
						
					$field = new Zend_Form_Element_Select($fieldname);
						
					$haystack = array();
					$optionsdata = explode("\n",$data["optionsdata"]);
					foreach ($optionsdata as $k=>$v) $haystack[$k] = trim($v);
						
					$field -> addMultiOption("",$this->_translate->_("---Выберите---"));

					foreach ($haystack as $value) {
						$field -> addMultiOption($value,$value);
					}
						
					$haystack[$this->_translate->_("---Выберите---")] = "";
						
					$field -> addValidator("InArray",true,array("haystack" => $haystack, "messages" => array("notInArray" => $this->_translate->_("Не выбрано ни одного значения"))));
						
					break;
						
				/**
				 * Список с множественным выбором
				 */
					
				case "Multiselect":
						
					$field = new Zend_Form_Element_Multiselect($fieldname);
						
					$haystack = array();
					$optionsdata = explode("\n",$data["optionsdata"]);
					foreach ($optionsdata as $k=>$v) $haystack[$k] = trim($v);

					foreach ($optionsdata as $value) {
						$field -> addMultiOption($value,$value);
					}
						
					$field -> addValidator("InArray",true,array("haystack" => $haystack, "messages" => array("notInArray" => $this->_translate->_("Не выбрано ни одного значения"))));
						
					break;
						
				/**
				 * Файл
				 */
					
				case "File":
						
					$field = new Zend_Form_Element_File($fieldname);
						
					if($data["filestypes"]=="Images") {
						$field -> addValidator("Extension",false,array("extension" => "png,jpg,gif,jpeg,bmp", "messages" => array("fileExtensionFalse" => $this->_translate->_("Файл '%value%' не является изображением"))));
					} elseif($data["filestypes"]=="Documents") {
						$field -> addValidator("Extension",false,array("extension" => "doc,xls,odt,docx,xlsx,pdf,txt", "messages" => array("fileExtensionFalse" => $this->_translate->_("Файл '%value%' не является документом"))));
					} elseif($data["filestypes"]=="Archives") {
						$field -> addValidator("Extension",false,array("extension" => "zip,rar,7z,gz,tgz", "messages" => array("fileExtensionFalse" => $this->_translate->_("Файл '%value%' не является файловым архивом"))));
					}
						
					//$field -> setDestination($this->paths["html"]."forms/files/");
					$field -> setValueDisabled(true);
						
					break;
						
				/**
				 * Refferer
				 */
					
				case "Refferer":
						
					$field = new Zend_Form_Element_Hidden($fieldname);
						
					if(isset($_SERVER["HTTP_REFERER"])) $field -> setValue($_SERVER["HTTP_REFERER"]);
						
					break;
						
				/**
				 * CAPTCHA
				 */
					
				case "Captcha":
						
					$captcha = Phorm_Captcha_Image::getCaptcha();
			
					$captcha -> setOptions(array("messages" => array("badCaptcha" => $this->_translate->_("Неверно указан код подтверждения"), 
																	 "missingID" => $this->_translate->_("Неверный идентификатор Captcha"))));
							    
					$field = new Zend_Form_Element_Captcha($fieldname,array("captcha" => $captcha));
						
					break;
						
				default:
						
					continue;	
					
			}
				
			// Если поле обязательно для заполнения
				
			if($data["isrequired"]=="yes") {
					
				$field -> setRequired(true)
					   -> addValidator("NotEmpty",true,array("messages" => array("isEmpty" => $this->_translate->_("Не заполнено поле"))));
					
			}
				
			// Устанавливаем заголовок и описание поля
				
			if($field instanceof Zend_Form_Element_Hidden) {
					
				$field -> removeDecorator("label") 
					   -> removeDecorator("HtmlTag");
				
			} else {
				
				$field -> setLabel($data["fieldname"])
					   -> setDescription($data["fieldtxt"]);
						   
			}
				
			$form -> addElement($field);
				
		}
			
		$form -> addElement(new Zend_Form_Element_Submit("Send",$this->_translate->_("Отправить")));
			
		$form -> setAttrib('enctype', 'multipart/form-data');
			
		return $form;
			
	}
	
	
	/**
	 * Сохраняет информацию о заполненной форме
	 * 
	 * @param array $data Массив данных
	 * @param array $forminfo Информация о форме
	 * @param Zend_form $form Объект формы
	 * 
	 * @return int Id записи
	 */
		
	public function saveEntry($data,$forminfo) {
			
		$entrydata = array("resourceid" => $forminfo["resourceid"],
						   "entrydate"  => time(), 
						   "entrydata"  => serialize($data), 
						   "userid"     => $this->_usersession->UserData["userid"]);
			
		if($this->_db->insert("pw_resources_forms_entries",$entrydata)) {
				
			$entryid = $this->_db->lastInsertId();
				
			$upload = new Zend_File_Transfer_Adapter_Http();
			foreach ($upload -> getFileInfo() as $fieldname=>$fileinfo) {
				move_uploaded_file($fileinfo["tmp_name"],"upload_forms/".$entryid."_".$fieldname.".".preg_replace("#^.*?\.([0-9a-z]{2,4})$#i","$1",$fileinfo["name"]));
			}
				
			if($forminfo["formemail"]!="") {
							
				$search  = array('%sitename%','%formname%','%formurl%','%siteurl%');
				$replace = array($this->_cnf["site"]["name"],
								 $forminfo["resourcename"],
								 'http://'.$_SERVER['HTTP_HOST'].$this->_cnf["site"]["url"].'/control/forms/view/entryid/'.$entryid.'/',
								 'http://'.$_SERVER['HTTP_HOST'].$this->_cnf["site"]["url"]);
								 
				$subject = str_replace($search,$replace,$this->_translate->_('Тема сообщения: Заполнена форма на сайте'));
				$body    = str_replace($search,$replace,$this->_translate->_('Текст сообщения: Заполнена форма на сайте'));
				
				if(isset($this->_cnf["resources"]["mail"]["charset"]) && $this->_cnf["resources"]["mail"]["charset"]!="UTF-8") {
					$subject = mb_convert_encoding($subject,$this->_cnf["resources"]["mail"]["charset"],"UTF-8");
					$body = mb_convert_encoding($body,$this->_cnf["resources"]["mail"]["charset"],"UTF-8");
				}
				
				$mail = new Zend_Mail($this->_cnf["resources"]["mail"]["charset"]);
				$mail->setBodyText($body);
				$mail->addTo($forminfo["formemail"]);
				$mail->setSubject($subject);
				$mail->send();
					
			}
 				
			return $entryid;
				
		}
			
		return false;
			
	}
	
	
	/**
	 * Возвращает список записей в форме
	 * 
	 * @param int $resourceid Id формы
	 * 
	 * @return array
	 */
		
	public function getEntriesList($resourceid) {
		
		$select = $this->_db->select()
				-> from(array('AA'=>'pw_resources_forms_entries'), new Zend_Db_Expr('SQL_CALC_FOUND_ROWS AA.*,BB.username,1 actions'))
				-> joinLeft(array('BB'=>'pw_users'),'AA.userid=BB.userid')
				-> order('AA.entryid DESC')
				-> where('AA.resourceid=?',$resourceid)
				-> limitPage($this->getCurrentPage(),$this->getPerPage());
			
		return $this->_db->fetchAll($select);
			
	}
		
		
	/**
	 * Возвращает информацию о записи в форме
	 * 
	 * @param int $entryid Id Записи
	 * 
	 * @return array
	 * @todo Убрать реплейсы ключей после разработки фронтенда
	 */
		
	public function getEntryInfo($entryid) {
		
		$select = $this->_db->select()
				-> from(array('AA'=>'pw_resources_forms_entries'))
				-> join(array('BB'=>'pw_resources'),'AA.resourceid=BB.resourceid',array('resourcename'))
				-> joinLeft(array('CC'=>'pw_users'),'AA.userid=CC.userid')
				-> where('AA.entryid=?',$entryid);
			
		if($row = $this->_db->fetchRow($select)) {
				
				$row["entrydata"] = Zend_Json::decode($row["entrydata"]);
				
				foreach ($row['entrydata'] as $k=>$v) {
					$row['entrydata'][preg_replace("#[^0-9]+#","",$k)] = $v;
					unset($row['entrydata'][$k]);
				}

				$row['fields'] = $this->getFieldsList($row['resourceid']);
				
				return $row;
				
		}
			
		return false;
			
	}
	
	
	/**
	 * Обновляет статус записи в форме
	 *
	 * @param int $entryid
	 * @param string $status
	 * @return boolean
	 */
	
	public function updateEntryStatus($entryid,$status='no') {
		
		return $this->_db->update('pw_resources_forms_entries',array('isopened'=>$status),'entryid='.(int)$entryid);
		
	}
	
}